package com.thirtydays.frame.util

/**
 * @创建者：小垚
 * @时间：2021/7/2216:47
 * @描述：
 */
object NumUtil {
    /**
     * 单位进位，中文默认为4位即（万、亿）
     */
    private const val UNIT_STEP = 4

    /**
     * 单位
     */
    private val CN_UNITS = mutableListOf("个", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千", "万")

    /**
     * 汉字
     */
    private val CN_CHARS = mutableListOf("零", "一", "二", "三", "四", "五", "六", "七", "八", "九")

    /**
     * 将阿拉伯数字转换为中文数字123=》一二三
     *
     * @param srcNum
     * @return
     */
    fun getCNNum(srcNum: String): String {
        var desCNNum = StringBuilder()
        srcNum.forEachIndexed { index, c ->
            desCNNum.append(CN_CHARS[c.toString().toInt()])
        }
        return desCNNum.toString()
    }

    /**
     * 数值转换为中文字符串 如2转化为贰
     */
    fun cvt(num: Long) = cvt(num, true)

    /**
     * 数值转换为中文字符串(口语化)
     *
     * @param num
     *            需要转换的数值
     * @param isColloquial
     *            是否口语化。例如12转换为'十二'而不是'一十二'。
     * @return
     */
    fun cvt(num: String, isColloquial: Boolean): String {
        val integer: Int
        val decimal: String
        val strs = StringBuffer(32)
        val splitNum = num.split(".")
        integer = splitNum[0].toInt() //整数部分
        decimal = splitNum[1] //小数部分

        val result1 = convert(integer.toLong(), isColloquial)
        result1.forEach {
            strs.append(it)
        }
        return if (decimal.toInt() == 0) { //小数部分为0时
            strs.toString()
        } else {
            val result2 = getCNNum(decimal) //例如5.32，小数部分展示三二，而不是三十二
            strs.append("点")
            strs.append(result2)
            strs.toString()
        }
    }

    /*
         * 对于int,long类型的数据处理
         */
    fun cvt(num: Long, isColloquial: Boolean): String {
        val result = convert(num, isColloquial)
        val strs = StringBuffer(32)
        result.forEach {
            strs.append(it)
        }
        return strs.toString()
    }

    /**
     * 将数值转换为中文
     *
     * @param num
     *            需要转换的数值
     * @param isColloquial
     *            是否口语化。例如12转换为'十二'而不是'一十二'。
     * @return
     */
    private fun convert(num: Long, isColloquial: Boolean): MutableList<String> {
        if (num < 10) { // 10以下直接返回对应汉字
            return mutableListOf(CN_CHARS[num.toInt()])
        }

        val chars = num.toString().toCharArray()
        if (chars.size > CN_UNITS.size) { // 超过单位表示范围的返回空
            return mutableListOf()
        }

        var isLastUnitStep = false // 记录上次单位进位

        val cnchars = ArrayList<String>(chars.size * 2) // 创建数组，将数字填入单位对应的位置

        for (pos in chars.indices.reversed()) { // 从低位向高位循环
            val ch = chars[pos]
            val cnChar = CN_CHARS[ch - '0'] // ascii2int 汉字
            val unitPos = chars.size - pos - 1 // 对应的单位坐标
            val cnUnit = CN_UNITS[unitPos] // 单位
            val isZero = ch == '0' // 是否为0
            val isZeroLow = pos + 1 < chars.size && chars[pos + 1] == '0' // 是否低位为0
            val isUnitStep = unitPos >= UNIT_STEP && unitPos % UNIT_STEP == 0 // 当前位是否需要单位进位
            if (isUnitStep && isLastUnitStep) { // 去除相邻的上一个单位进位
                val size: Int = cnchars.size
                cnchars.removeAt(size - 1)
                if (CN_CHARS[0] != cnchars[size - 2]) { // 补0
                    cnchars.add(CN_CHARS[0])
                }
            }
            if (isUnitStep || !isZero) { // 单位进位(万、亿)，或者非0时加上单位
                cnchars.add(cnUnit)
                isLastUnitStep = isUnitStep
            }
            if (isZero && (isZeroLow || isUnitStep)) { // 当前位为0低位为0，或者当前位为0并且为单位进位时进行省略
                continue
            }
            cnchars.add(cnChar)
            isLastUnitStep = false
        }

        cnchars.reverse()
        // 清除最后一位的0
        // 清除最后一位的0
        val chSize: Int = cnchars.size
        val chEnd = cnchars[chSize - 1]
        if (CN_CHARS[0] == chEnd || CN_UNITS[0] == chEnd) {
            cnchars.removeAt(chSize - 1)
        }

        // 口语化处理
        if (isColloquial) {
            val chFirst = cnchars[0]
            val chSecond = cnchars[1]
            if (chFirst == CN_CHARS[1] && chSecond.startsWith(CN_UNITS[1])) { // 是否以'一'开头，紧跟'十'
                cnchars.removeAt(0)
            }
        }
        return cnchars
    }

}